﻿using ICodeShare.UI.Interactivity.Common;
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;
using System.Windows.Media;
using Windows7.Multitouch.Manipulation;

namespace ICodeShare.UI.Interactivity
{
    public class TranslateRotateScaleBehavior : Behavior<FrameworkElement>
    {
        #region Constructor
        public TranslateRotateScaleBehavior()
        {
            CanTranslate = true;
            CanRotate = true;
            CanScale = true;
        }
        #endregion

        #region Fields
        ContextualElementTracker elementTracker;

        TransformGroup transformGroup;
        TranslateTransform translateTransform;
        ScaleTransform scaleTransform;
        RotateTransform rotateTransform;

        double xOffset = 0;
        double yOffset = 0;
        double minScale = 1;
        double maxScale = 5;
        #endregion

        #region Properties
        public Canvas SpatialContext { get; set; }
        public UIElement ContextedElement { get; set; }
        public double LeftBound
        {
            get
            {
                return 0 - xOffset;
            }
        }
        public double RightBound
        {
            get
            {
                return LeftBound + SpatialContext.RenderSize.Width;
            }
        }
        public double TopBound
        {
            get
            {
                return 0 - yOffset;
            }
        }
        public double BottomBound
        {
            get
            {
                return TopBound + SpatialContext.RenderSize.Height;
            }
        }
        #endregion

        #region Dependency Properties
        public static readonly DependencyProperty CanTranslateProperty =
            DependencyProperty.Register("CanTranslate", typeof(bool), typeof(TranslateRotateScaleBehavior), null);

        public bool CanTranslate
        {
            get { return (bool)GetValue(CanTranslateProperty); }
            set { SetValue(CanTranslateProperty, value); }
        }

        public static readonly DependencyProperty CanRotateProperty =
            DependencyProperty.Register("CanRotate", typeof(bool), typeof(TranslateRotateScaleBehavior), null);

        public bool CanRotate
        {
            get { return (bool)GetValue(CanRotateProperty); }
            set { SetValue(CanRotateProperty, value); }
        }

        public static readonly DependencyProperty CanScaleProperty =
            DependencyProperty.Register("CanScale", typeof(bool), typeof(TranslateRotateScaleBehavior), null);

        public bool CanScale
        {
            get { return (bool)GetValue(CanScaleProperty); }
            set { SetValue(CanScaleProperty, value); }
        }

        //Dependency property for setting the Minimum Scale Size
        public static readonly DependencyProperty MinimumScaleProperty =
            DependencyProperty.Register("MinimumScale", typeof(int),
                                        typeof(TranslateRotateScaleBehavior), null);

        public int MinimumScale
        {
            get { return (int)GetValue(MinimumScaleProperty); }
            set { SetValue(MinimumScaleProperty, value); }
        }

        //Dependency property for enabling the Maximum Scale Size
        public static readonly DependencyProperty MaximumScaleProperty =
            DependencyProperty.Register("MaximumScale", typeof(int),
                                        typeof(TranslateRotateScaleBehavior), null);

        public int MaximumScale
        {
            get { return (int)GetValue(MaximumScaleProperty); }
            set { SetValue(MaximumScaleProperty, value); }
        }

        //Dependency property for setting the Minimum Scale Size
        public static readonly DependencyProperty XLocationProperty =
            DependencyProperty.Register("XLocation", typeof(int),
                                        typeof(TranslateRotateScaleBehavior), null);

        public int XLocation
        {
            get { return (int)GetValue(XLocationProperty); }
            set { SetValue(XLocationProperty, value); }
        }

        //Dependency property for enabling the Maximum Scale Size
        public static readonly DependencyProperty YLocationProperty =
            DependencyProperty.Register("YLocation", typeof(int),
                                        typeof(TranslateRotateScaleBehavior), null);

        public int YLocation
        {
            get { return (int)GetValue(YLocationProperty); }
            set { SetValue(YLocationProperty, value); }
        }
        #endregion


        #region Scalar Properties
        //We expose these so that other input channels other than our behavior can also use them if they want to augment position in any way.

        public double X
        {
            get { return translateTransform.X; }
            set
            {
                if (value < LeftBound)
                {
                    value = LeftBound;
                }
                else if (value > RightBound)
                {
                    value = RightBound;
                }
                translateTransform.X = value;
            }
        }
        public double Y
        {
            get { return translateTransform.Y; }
            set
            {
                if (value < TopBound)
                {
                    value = TopBound;
                }
                else if (value > BottomBound)
                {
                    value = BottomBound;
                }
                translateTransform.Y = value;
            }
        }
        public double Scale
        {
            get { return scaleTransform.ScaleX; ; }
            set
            {
                if (value < minScale)
                    value = minScale;
                if (value > maxScale)
                    value = maxScale;
                scaleTransform.ScaleX = value;
                scaleTransform.ScaleY = value;
            }
        }
        public double Angle
        {
            get { return rotateTransform.Angle; }
            set { rotateTransform.Angle = value; }
        }
        #endregion

        #region Inheritance Overrides
        protected override void OnAttached()
        {
            base.OnAttached();

            this.AssociatedObject.RenderTransformOrigin = new Point(0.5, 0.5);

            transformGroup = new TransformGroup();
            rotateTransform = new RotateTransform();
            scaleTransform = new ScaleTransform();
            translateTransform = new TranslateTransform();

            transformGroup.Children.Add(rotateTransform);
            transformGroup.Children.Add(scaleTransform);
            transformGroup.Children.Add(translateTransform);

            this.AssociatedObject.RenderTransform = transformGroup;

            if (!Windows7.Multitouch.TouchHandler.DigitizerCapabilities.IsMultiTouchReady)
            {
                MessageBox.Show("Multitouch is not availible");
            }

            if (this.AssociatedObject.Parent.GetType() != typeof(Canvas))
            {
                MessageBox.Show("Sorry, the MoveZoomRotateContainerBehavior can only be applied to objects who have parents of CLR type Canvas at this time.");
            }

            SpatialContext = this.AssociatedObject.Parent as Canvas;
            ContextedElement = this.AssociatedObject as UIElement;

            elementTracker = new ContextualElementTracker(this, this.AssociatedObject);
            elementTracker.ManipulationCompleted += OnTouchManipulation;

            this.AssociatedObject.Loaded += (s, e) =>
            {
                xOffset = this.GetXOffset();
                yOffset = this.GetYOffset();

                if (MinimumScale > 0)
                    minScale = MinimumScale / this.AssociatedObject.ActualWidth;
                if (MaximumScale > 0)
                    maxScale = MaximumScale / this.AssociatedObject.ActualHeight;

                if (MinimumScale > 0 && MinimumScale > this.AssociatedObject.ActualWidth)
                    Scale = minScale;
                if (MaximumScale > 0 && MaximumScale < this.AssociatedObject.ActualWidth)
                    Scale = maxScale;

                if (XLocation > 0)
                    this.X = XLocation - xOffset;

                if (YLocation > 0)
                    this.Y = YLocation - yOffset;


            };

        }
        protected override void OnDetaching()
        {
            base.OnDetaching();
        }
        #endregion

        #region Event Subscription Call Site
        public void OnTouchManipulation(object sender, ManipulationDeltaEventArgs args)
        {
            if (CanTranslate)
            {
                this.X += args.TranslationDelta.Width;
                this.Y += args.TranslationDelta.Height;
            }

            if (CanRotate)
            {
                this.Angle += args.RotationDelta * 180 / Math.PI;

            }

            if (CanScale)
            {
                this.Scale *= args.ScaleDelta;
            }


        }
        #endregion
    }
}
